%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "common.h"
#include "yy.h"


extern int yyparse ();

int fatalError=0;
char *currentFile = NULL;

#define SRC_BUF_SIZE    4096
char srcBuf[SRC_BUF_SIZE], emptySrc = 1;

/* --- constant convertion types --- */
enum {C_OCT, C_HEX, C_CHAR, C_BIN};
int  aConstant(char *s, int type);
int  constantType(char *s);
void addSrcCode(void);
void updateSourceInfo(char *);
                                 
%}

identifier-nondigit                           [a-zA-Z_]
digit                                         [0-9]
identifier                                    ({identifier-nondigit}({identifier-nondigit}|{digit})*)

hexadecimal-prefix                            (0x|0X)
nonzero-digit                                 [1-9]
octal-digit                                   [0-7]
hexadecimal-digit                             [0-9a-fA-F]
decimal-constant                              ({nonzero-digit}({digit})*)
octal-constant                                (0({octal-digit}*)) 
hexadecimal-constant                          ({hexadecimal-prefix}({hexadecimal-digit}+))


floating-constant                             ({decimal-floating-constant}|{hexadecimal-floating-constant})
decimal-floating-constant                     (({fractional-constant}{exponent-part}?)|{digit-sequence}{exponent-part})
hexadecimal-floating-constant                 ({hexadecimal-prefix}({hexadecimal-fractional-constant}|{hexadecimal-digit-sequence}){binary-exponent-part})
binary-exponent-part                          ([pP]{sign}?{digit-sequence})
fractional-constant                           {digit-sequence}?\.{digit-sequence}
sign                                          [+-]
exponent-part                                 ([eE]{sign}?{digit-sequence})
digit-sequence                                ({digit}+)
hexadecimal-digit-sequence                    ({hexadecimal-digit}+)
hexadecimal-fractional-constant               ({hexadecimal-digit-sequence}?\.{hexadecimal-digit-sequence})




SP                                            [ \t\v\f\015]
newline                                       [\n\r]

%x COMMENT

%%
"//".*                  	     { /* 单行注释, 直接删掉 */ }
"/*"                             { BEGIN(COMMENT); }
<COMMENT>"*/"                	 { BEGIN(INITIAL); }
<COMMENT>{newline}         		 { yylineno++; }
<COMMENT>.                 		 { /* C style comments, remove it. */ } 

{decimal-constant}               { addSrcCode(); yylval.i = atoi(yytext); return INT_CONSTANT; }
{octal-constant}                 { addSrcCode(); yylval.i = aConstant(yytext, C_HEX); return INT_CONSTANT; }
{hexadecimal-constant}           { addSrcCode(); yylval.i = aConstant(yytext, C_OCT); return INT_CONSTANT; }
{floating-constant}              { addSrcCode(); yylval.f = atof(yytext); return FLOAT_CONSTANT;}


"void" 					         { addSrcCode(); return VOID; }						
"int" 					         { addSrcCode(); return INT; }						
"float"     			         { addSrcCode(); return FLOAT; }						
"break"                          { addSrcCode(); return BREAK; }
"const"                          { addSrcCode(); return CONST; }
"continue"                       { addSrcCode(); return CONTINUE; }
"else"                           { addSrcCode(); return ELSE; }
"for"                            { addSrcCode(); return FOR; }
"if"                             { addSrcCode(); return IF; }
"return"                         { addSrcCode(); return RETURN; }
"while"                          { addSrcCode(); return WHILE; }


{identifier}                     { addSrcCode(); yylval.s = dupStr(yytext); return IDENTIFIER; }

                                 
"=="                             { addSrcCode(); yylval.i = EQ_OP; return EQUALITY_OP; }
"!="                             { addSrcCode(); yylval.i = NE_OP; return EQUALITY_OP; }
"<="                             { addSrcCode(); yylval.i = LE_OP; return RELATIONAL_OP; }
">="                             { addSrcCode(); yylval.i = GE_OP; return RELATIONAL_OP; }
[<>]                             { addSrcCode(); yylval.i = *yytext; return RELATIONAL_OP; }
"||"                             { addSrcCode(); return OR_OP; }
"&&"                             { addSrcCode(); return AND_OP; }
                                 
                                 
[;{}=(),:&|!~*/%^@+-]	         { if ( *yytext != '{' && *yytext != '}' )  addSrcCode(); return *yytext; }
                                 
"["						         { addSrcCode(); return '['; }
"]"						         { addSrcCode(); return ']'; }
                                 
{SP}+                            { addSrcCode(); }
                                 
{newline}                        { yylineno++; }
                                 
.                                { printf("illegal character! ... 0x%02X '%s' in line #%d\n", 
                                     *yytext, yytext, yylineno); 
                                 }
						
%%

/************************************************************/
int _main(char *filename)
{
	currentFile = dupStr(filename);
    yyin = fopen(filename, "r");

    if ( yyin == NULL )
    {
        printf("can't open file - %s!", filename);
        exit (99);
    }
   
    yylineno  = 1;
    if ( yyparse() )     // if fail to parse, stop!
    {
        printf("yyparse stopped at #Line %d\n", yylineno);
        exit (99);
    }
	
	free(currentFile);
    return fatalError; 
}

void addSrcCode(void)
{
	if ( emptySrc )
		srcBuf[0] = '\0';
	
	if ( (strlen(srcBuf) + yyleng) < SRC_BUF_SIZE )
	{
		strcat(srcBuf, yytext);	
		emptySrc = 0;
	}
}

int aConstant(char *s, int type)
{
    int n = 0;
    switch ( type )
    {
        case C_HEX:	sscanf (s, "%x", &n); 
					break;
					
        case C_OCT: for (; *s >= '0' && *s < '8'; s++)
						n = (n*8) + *s - '0';
					break;
	}
    return n;
}

char *getSrcCode(void)
{
	if ( emptySrc )
		return NULL;

	emptySrc = 1;
	return skipSP(srcBuf);
}

void updateSourceInfo(char *file)
{
	int i = 0;
	
	while ( !isdigit(file[i]) ) i++;
	yylineno = atoi(&file[i]);
	while (  isdigit(file[i]) ) i++;
	
	free(currentFile);
	currentFile = dupStr(skipSP(&file[i]));
	emptySrc = 1;
}


/************************************************************/
int yywrap (void) 
{ 
    fclose (yyin);
    return -1;
}

/************************************************************/
int yyerror (char *s)
{
    fflush (stdout);
    fprintf (stdout, "\n%s:%d: %s: token -> '%s'\n", currentFile, yylineno, s, yytext);
    fatalError++;
    return 0;
}
